#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "raylib.h"
#include "pub_lib.h"
#include "FreeImage.h"
#include "image.h"
#include "dpi_algo.h"

const int screenWidth = 1024;
const int screenHeight = 768;

cpu_image effect_data;
run_state gstate = STATE_IDLE;

fft_data_struc* gfft_ptr = NULL;
char g_select_str_default[] = "press 'enter' to confirm, 'c' to clear, 'z' to undo";
char g_select_str[128];
#define set_select_str_default() strcpy(g_select_str, g_select_str_default)

#define MAX_SELECT_POINTS 10
int g_select_num = 0;
static Vector2 gselect_pos[MAX_SELECT_POINTS];
static float gradius = 1.0f;

static float g_wiener_K = 1.0f;
static fftwf_complex* g_wiener_filter = NULL;

char* hint_right = NULL;
char hint_left[128] = "image size";

static char mean_image[] = "Fig0507(a)(ckt-board-orig).tif"; //example 5.2
static char mean_noise_image[] = "Fig0507(b)(ckt-board-gauss-var-400).tif";
static char stat_image[] = "Fig0510(a)(ckt-board-saltpep-prob.pt05).tif";
static char adaptive_local_image[] = "Fig0513(a)(ckt_gaussian_var_1000_mean_0).tif";
static char adaptive_median_image[] = "Fig0514(a)(ckt_saltpep_prob_pt25).tif";
static char freq_notch_image[] = "Fig0519(a)(florida_satellite_original).tif";
static char freq_degradation_image[] = "Fig0525(b)(aerial_view_turb_c_0pt0025).tif";

#define MAX_CMD_NUM 7
const char command_str_en[MAX_CMD_NUM][MAX_HINT_STRING_LEN] =
{
	//5.3 Spatial Filtering
	"1. Mean Filters", //example 5.2
	"2. Order-Statistic", //example 5.3
	"3. Adaptive Filters", //example 5.4, 5.5

	//5.4 Frequency Filtering
	"4. Notch Filter", //example 5.8

	//5.6 Estimatiing the Degradation Function
	"5. blurring of motion", //example 5.10

	//5.7 Inverse Filtering
	"6. Inverse Filter", //example 5.11

	//5.8
	"7. Wiener" //example 5.13, Minimum Mean Squares, MMS
	//"8. comparison of Wiener"
};

const char command_str_cn[MAX_CMD_NUM][MAX_HINT_STRING_LEN] =
{
	"1. 空间均值滤波",
	"2. 空间统计排序滤波",
	"3. 空间自适应滤波",

	"4. 频域陷波滤波",
	"5. 运动导致的图像模糊",
	"6. 频域直接逆滤波",
	"7. 频域最小均方差滤波 Wiener"
	//"8. 逆滤波对比维纳小二乘滤波"
};

void init_effect_data(void)
{
	memset(&effect_data, 0, sizeof(cpu_image));
	effect_data.win_width = screenWidth;
	effect_data.win_height = screenHeight;
	effect_data.fb_pixels = effect_data.win_width * effect_data.win_height;
	effect_data.startx = 10;
	effect_data.starty = 30;
	effect_data.left_max = get_max_pixel(screenWidth, 0.3f);
	effect_data.right_max = get_max_pixel(screenWidth, 0.7f);
	effect_data.right_image_max = effect_data.right_max;;

	effect_data.split_line = effect_data.startx + effect_data.left_max + 5;
	effect_data.lx = effect_data.startx;
	effect_data.rx = effect_data.split_line + 5;
}

void init_fb(void)
{
	effect_data.frame_buf = calloc(effect_data.fb_pixels, sizeof(Color));
}

/*
 * 打开图片，读入图片数据
 * 原始图片信息:  ori
 * 左边显示的小图片: left
 * 右边显示的大图片: right
 * 右边显示的大图片的更改后的数据: rchg
 * 右边显示的大图片，中间计算的结果：rchg_data
 * */
int init_effect(char* path, int right_window_num)
{
	effect_data.right_window_num = right_window_num;
	const char* ext = GetFileExtension(path);

	FIBITMAP* ori;
	ori = open_img(path);
	if (!ori)
		return -1;
	if (!strcmp(ext, ".tif")) {
		read_img(ori, &effect_data);
		if (effect_data.format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) {
			printf("only support [0, 255] 1 byte TIF image\n");
			close_img(ori);
			return -1;
		}
	}
	effect_data.show_histo = 0;
	effect_data.order = 0;
	effect_data.ori = ori;
	effect_data.left = ori;
	effect_data.right = ori;

	//check if need scale of left image
	int max = effect_data.left_max; //最长或最宽不超过360
	int neww = max, newh = max;
		if ( effect_data.image_width > max || effect_data.image_height > max) {
		cal_scaled_val(max, effect_data.image_width, effect_data.image_height,
				&neww, &newh);
		effect_data.left = FreeImage_Rescale(ori, neww, newh, FILTER_BILINEAR);
	}

	//check if need scale of right image
	if(right_window_num == 1)
		effect_data.right_image_max = get_max_pixel(screenWidth, 0.7f);
	else
		effect_data.right_image_max = split_right_window(effect_data.win_width, 0.7f);

	max = effect_data.right_image_max;
	neww = effect_data.image_width;
	newh = effect_data.image_height;
	if (effect_data.image_width > max || effect_data.image_height > max) {
		cal_scaled_val(max, effect_data.image_width, effect_data.image_height,
			&neww, &newh);
		effect_data.right = FreeImage_Rescale(ori, neww, newh, FILTER_BILINEAR);
	}
	sprintf(hint_left, "ori:%dx%d  chg:%dx%d",
		effect_data.image_width, effect_data.image_height, neww, newh);

	effect_data.rchg = FreeImage_Copy(effect_data.right, 0, 0, neww, newh);
	effect_data.pri  = FreeImage_Copy(effect_data.right, 0, 0, neww, newh);

	//int data[w][h]
	effect_data.rchg_data = calloc(neww * newh, sizeof(float));

	effect_data.image_size = GetPixelDataSize(effect_data.image_width,
		effect_data.image_height, effect_data.format);
	effect_data.pix_len = get_pixel_bytes(effect_data.image_width,
		effect_data.image_height, effect_data.image_size);

	return 0;
}

void unload_image(void)
{
	if(effect_data.left != effect_data.ori)
		close_img(effect_data.left);
	if(effect_data.right != effect_data.ori)
		close_img(effect_data.right);
	if(effect_data.ori)
		close_img(effect_data.ori);
	if(effect_data.rchg)
		close_img(effect_data.rchg);
	if(effect_data.pri)
		close_img(effect_data.pri);

	if(g_wiener_filter) {
		fftwf_free(g_wiener_filter);
	}

	if(effect_data.rchg_data)
		free(effect_data.rchg_data);
}

void destroy_effect(void)
{
	free(effect_data.frame_buf);
	unload_image();
}

void switch_next_image(char* filename, int right_window_num)
{
	int ret;
	char path[256];

	clear_fb(&effect_data, RAYWHITE);
	unload_image();
	get_full_path(IMAGE_PATH, filename, path);
	ret = init_effect(path, right_window_num);
	if (ret)
		return;
	show_image(effect_data.left, &effect_data,\
		effect_data.startx, effect_data.starty);
}

static void smean_filter(FIBITMAP* ori, FIBITMAP* chg,
	int filter_type, int dim, void* user_data)
{
	if(filter_type == 0)
		image_filter_avg(ori, chg, dim);
	else
		image_filter_geo_mean(ori, chg, dim);
}

// example 5.2
static void spatial_mean_filter(void)
{
	int w, h;
	w = FreeImage_GetWidth(effect_data.right);
	h = FreeImage_GetHeight(effect_data.right);

	//figure 5.7
	//pos 1, show histogram
	get_histogram(effect_data.ori, effect_data.ori_histo);

	//pos 2, filter_type = 0, dim = 3
	show_filtered_image_nodata(mean_noise_image, 2, smean_filter, 0, 3);

	//pos 3, filter_type = 1, dim = 3
	show_filtered_image_nodata(mean_noise_image, 3, smean_filter, 1, 3);

	//figure 5.7 (a), pos 4
	show_scaled_img(mean_image, 4);
}

static void draw_stats(sp_filter_stat type, char* file, int w, int h, int pos)
{
	FIBITMAP *ori, *chg, *show;
	char path[256];

	//3. Max
	get_full_path(IMAGE_PATH, file, path);
	ori = open_img(path);
	if(!ori)
		return;
	chg = copy_img(ori);

	image_filter_stat_common(ori, chg, 3, type);
	show = FreeImage_Rescale(chg, w, h, FILTER_BILINEAR);
	draw_right_image(show, pos);

	close_img(show);
	close_img(ori);
	close_img(chg);
}

//example 5.3
static void spatial_stat_filter(void)
{
	int w, h;
	w = FreeImage_GetWidth(effect_data.right);
	h = FreeImage_GetHeight(effect_data.right);

	//1. histogram
	get_histogram(effect_data.ori, effect_data.ori_histo);

	//2. Median filter
	draw_stats(SPSTAT_MEDIAN, "Fig0510(a)(ckt-board-saltpep-prob.pt05).tif",
		w, h, 2);
	
	//3. Max
	draw_stats(SPSTAT_MAX, "Fig0508(a)(circuit-board-pepper-prob-pt1).tif",
		w, h, 3);

	//4. Min
	draw_stats(SPSTAT_MIN, "Fig0508(b)(circuit-board-salt-prob-pt1).tif",
		w, h, 4);
}

//example 5.4, Adaptive, local noise reduction filter
//example 5.5, Adaptive, median filter

//type = 0, local noise reduction filter
//type = 1, Adaptive, median filter
static void sadaptive_filter(FIBITMAP* ori, FIBITMAP* chg,
	int filter_type, int dim, void* user_data)
{
	if(filter_type == 0) {
		//variance = 1000
		spatial_local_adaptive(ori, chg, dim, 1000);
	} else {
		//smax = dim
		spatial_median_adaptive(ori, chg, dim);
	}
}

void spatial_adaptive_local_filter(void)
{
	int w, h;
	w = FreeImage_GetWidth(effect_data.right);
	h = FreeImage_GetHeight(effect_data.right);

	//1. histogram
	get_histogram(effect_data.ori, effect_data.ori_histo);

	//2. local noise reduction filter
	//pos = 2, filter_type = 0, dim = 7
	show_filtered_image_nodata(adaptive_local_image, 2, sadaptive_filter, 0, 3);

	//3. noise image
	show_scaled_img(adaptive_median_image, 3);

	// media filter
	// pos = 4, filter_type = 1, dim = 7
	show_filtered_image_nodata(adaptive_median_image, 4, sadaptive_filter, 1, 7);
}

//w,h: image width and height
float calc_sin_noise_r(Vector2* data, int num, int w, int h)
{
	if(!num) //error
		return 1.0f;
	float x, y;
	x = data[0].x - effect_data.rx;
	y = data[0].y - effect_data.starty;
	//x, y of image center
	float cx = (float)w / 2;
	float cy = (float)h / 2;
	float ret;
	ret = (x - cx) * (x - cx) + (y - cy) * (y - cy);
	ret = sqrtf(ret);
	printf("(%.3f, %.3f), r = %.3f\n", x, y, ret);
	return ret;
}

#if 0
//example 5.6
static void freq_br_filter(void)
{
	int w, h;
	w = FreeImage_GetWidth(effect_data.ori);
	h = FreeImage_GetHeight(effect_data.ori);

	hint_right = "select one point of circle, press space continue";
	gstate = STATE_WAIT_NEXT;
	//only show one figure: spectrum, used for selecting point
	//centered = 1, windows 1, threshold = 160
	gfft_ptr = draw_spectrum(effect_data.ori, 1, 1, 160, w, h);
}

static void freq_br_filter_all(void)
{
	switch_next_image(freq_br_image, 4);

	int w, h, nw, nh;
	w = FreeImage_GetWidth(effect_data.ori);
	h = FreeImage_GetHeight(effect_data.ori);
	nw = FreeImage_GetWidth(effect_data.right);
	nh = FreeImage_GetHeight(effect_data.right);
	float scale = (float)nw / w;
	gradius *= scale;

	effect_data.order = 1;
	hint_right = "Bandreject filter";

	//1. spectrum, figure 5.16 (b)
	show_scaled_data(gfft_ptr->s_norm, 1, nw, nh);

	float r = calc_sin_noise_r(gselect_pos, g_select_num, w, h);
	//2. noise pattern, figure 5.17
	br_filter_image(gfft_ptr, effect_data.ori, FREQ_FILTER_BTW, r, 5, 4, 1);
	show_scaled_data(gfft_ptr->image, 2, nw, nh); //show at window 2

	//3. figure 5.16 (d)
	//Butterworth bandreject image, width = 5, order = 4
	br_filter_image(gfft_ptr, effect_data.ori, FREQ_FILTER_BTW, r, 5, 4, 0);
	show_scaled_data(gfft_ptr->image, 3, nw, nh); //show at window 3

	//4. Spectrum Bandreject image
	//centered = 1, windows 4, threshold = 160
	calc_draw_spectrum(gfft_ptr, 1, 4, 160, nw, nh);

	//clean data
	g_select_num = 0;
	gstate = STATE_FINISH;
	destroy_fft_data(gfft_ptr);
	gfft_ptr = NULL;
}
#endif

static void freq_notch_filter(void)
{
	int w, h, nw, nh;
	w = FreeImage_GetWidth(effect_data.ori);
	h = FreeImage_GetHeight(effect_data.ori);
	nw = FreeImage_GetWidth(effect_data.right);
	nh = FreeImage_GetHeight(effect_data.right);

	//figure 1, spectrum
	//centered = 1, windows 1, threshold = 0
	gfft_ptr = draw_spectrum(effect_data.ori, 1, 1, 0, nw, nh);

	//figure 2, filtered image, 5.19e"
	//Notch Bandreject, vertical,
	fftwf_complex* filter = recnorch_default(1, RECNOTCH_MODE_VER, w, h);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	show_scaled_data(gfft_ptr->image, 2, nw, nh); //show at window 2

	//figure 3, noise image
	filter = recnorch_default(0, RECNOTCH_MODE_VER, w, h);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	show_scaled_data(gfft_ptr->image, 3, nw, nh); //show at window 3

	//clean data
	destroy_fft_data(gfft_ptr);
	gfft_ptr = NULL;
}

//example 5.10
void freq_blur_by_motion(void)
{
	int w, h;
	w = FreeImage_GetWidth(effect_data.ori);
	h = FreeImage_GetHeight(effect_data.ori);

	gfft_ptr = init_fft_data(w, h);
	fftwf_complex* filter = freq_modeling_a(w, h, 0.1, 0.1, 1);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	draw_right_data(gfft_ptr->image, 1);

	//fill_image_data(effect_data.ori, gfft_ptr->image);
	//FreeImage_Save(FIF_TIFF, effect_data.ori, "changed.tif", 0);

	destroy_fft_data(gfft_ptr);
	gfft_ptr = NULL;
}

//example 5.11, Inverse filtering
void freq_inverse_direct(void)
{
	int w, h, nw, nh;
	w = FreeImage_GetWidth(effect_data.ori);
	h = FreeImage_GetHeight(effect_data.ori);
	nw = FreeImage_GetWidth(effect_data.right);
	nh = FreeImage_GetHeight(effect_data.right);

	gfft_ptr = init_fft_data(w, h);
	//1. full size filter
	//k = 0.0025
	fftwf_complex* filter = freq_degradation_a(w, h, 0.0025f, 0);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	//log_float_data(gfft_ptr->image_data, gfft_ptr->image, w * h);
	show_scaled_data(gfft_ptr->image, 1, nw, nh);

	//2. r = 40
	filter = freq_degradation_a(w, h, 0.0025f, 40);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	show_scaled_data(gfft_ptr->image, 2, nw, nh);

	//3. r = 60, best effect
	filter = freq_degradation_a(w, h, 0.0025f, 60);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	show_scaled_data(gfft_ptr->image, 3, nw, nh);

	//4. r = 75
	filter = freq_degradation_a(w, h, 0.0025f, 75);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	//log_float_data(gfft_ptr->image_data, gfft_ptr->image, w * h);
	show_scaled_data(gfft_ptr->image, 4, nw, nh);

	destroy_fft_data(gfft_ptr);
	gfft_ptr = NULL;
}

static void freq_degradation_wiener_filter(void)
{
	int w, h, nw, nh;
	w = FreeImage_GetWidth(effect_data.ori);
	h = FreeImage_GetHeight(effect_data.ori);
	nw = FreeImage_GetWidth(effect_data.right);
	nh = FreeImage_GetHeight(effect_data.right);

	fftwf_complex* filter = freq_degradation_wiener(w, h, g_wiener_filter, g_wiener_K);
	common_filter_image(gfft_ptr, effect_data.ori, filter);
	show_scaled_data(gfft_ptr->image, 2, nw, nh);

	sprintf(hint_left, "wiener filter K = %.1f", g_wiener_K);
	hint_right = hint_left;
}

void handle_key_down_up(int cmd)
{
	if (effect_data.cmd != 7 && effect_data.cmd != 8)
		return;

	if(cmd == KEY_DOWN) {
		g_wiener_K -= 0.1;
		if (g_wiener_K < -1)
			return;
	} else {
		g_wiener_K += 0.1;
		if (g_wiener_K > 2)
			return;
	}

	freq_degradation_wiener_filter();
}


void handle_key_space(void)
{
	if(gstate != STATE_WAIT_NEXT)
		return;

	switch(effect_data.cmd) {
		default:
			break;
	}
}

void special_effect(int cmd)
{
	//repeate press same key
	if (effect_data.cmd == cmd)
		return;

	if(gstate != STATE_WAIT_NEXT)
		g_select_num = 0;

	if(cmd <= MAX_CMD_NUM) {
		effect_data.cmd = cmd;
		hint_right = (char*)command_str_en[cmd - 1];
		SetWindowTitle(command_str_cn[cmd - 1]);
		printf("%s\n", command_str_cn[cmd - 1]);

		if(gfft_ptr) {
			destroy_fft_data(gfft_ptr);
			gfft_ptr = NULL;
		}
		if(g_wiener_filter) {
			fftwf_free(g_wiener_filter);
			g_wiener_filter = NULL;
		}
	}

	int w, h, nw, nh;
	switch (cmd) {
	case 1: //mean filter
		switch_next_image(mean_noise_image, 4);
		spatial_mean_filter();
		break;
	case 2: //Order-Statistic Filters
		switch_next_image(stat_image, 4);
		spatial_stat_filter();
		break;
	case 3:
		switch_next_image(adaptive_local_image, 4);
		spatial_adaptive_local_filter();
		break;
	case 4:
		switch_next_image(freq_notch_image, 4);
		freq_notch_filter();
		break;
	case 5:
		switch_next_image("Fig0526(a)(original_DIP).tif", 1);
		freq_blur_by_motion();
		break;
	case 6:
		switch_next_image(freq_degradation_image, 4);
		freq_inverse_direct();
		break;
	case 7:
		switch_next_image(freq_degradation_image, 4);
		w = FreeImage_GetWidth(effect_data.ori);
		h = FreeImage_GetHeight(effect_data.ori);
		nw = FreeImage_GetWidth(effect_data.right);
		nh = FreeImage_GetHeight(effect_data.right);

		g_wiener_K = 1.0f;
		gfft_ptr = init_fft_data(w, h);
		g_wiener_filter = freq_degradation_a(w, h, 0.0025f, 60);
		common_filter_image(gfft_ptr, effect_data.ori, g_wiener_filter);
		show_scaled_data(gfft_ptr->image, 1, nw, nh);

		//common_filter_image free g_wiener_filter
		g_wiener_filter = freq_degradation_a(w, h, 0.0025f, 60);
		freq_degradation_wiener_filter();
		break;

	case 8:
#if 0
		switch_next_image("Fig0529(g).tif", 4);
		w = FreeImage_GetWidth(effect_data.ori);
		h = FreeImage_GetHeight(effect_data.ori);
		nw = FreeImage_GetWidth(effect_data.right);
		nh = FreeImage_GetHeight(effect_data.right);

		g_wiener_K = 0.0f;
		gfft_ptr = init_fft_data(w, h);
		g_wiener_filter = freq_modeling_a(w, h, 0.1, 0.1, 1);
		reciprocal_convert(g_wiener_filter, w, h);
		common_filter_image(gfft_ptr, effect_data.ori, g_wiener_filter);
		show_scaled_data(gfft_ptr->image, 1, nw, nh);

		//common_filter_image free g_wiener_filter
		g_wiener_filter = freq_modeling_a(w, h, 0.1, 0.1, 1);
		reciprocal_convert(g_wiener_filter, w, h);
		freq_degradation_wiener_filter();
#endif
		break;
	case KEY_DOWN:
		handle_key_down_up(cmd);
		break;
	case KEY_UP:
		handle_key_down_up(cmd);
		break;
	case KEY_SPACE:
		handle_key_space();
		break;
	default:
		hint_right = "not support command";
		break;
	}//end switch
}

static void draw_titles(void)
{
	switch(effect_data.cmd) {
		case 1://figure 5.7
			draw_title("Gaussian noise added", 1);
			draw_right_histo(effect_data.ori_histo, 1);
			draw_title("Arithmetric mean, 5.7c", 2);
			draw_title("Geometric mean, 5.7d", 3);
			draw_title("original 5.7a", 4);
			break;

		case 2: //figure 5.10 - 5.11
			draw_title("noise histogram", 1);
			draw_right_histo(effect_data.ori_histo, 1);
			draw_title("stat median, 5.10b", 2);
			draw_title("stat max, 5.11a", 3);
			draw_title("stat min, 5.11b", 4);
			break;

		case 3: //figure 5.13 - 5.14
			draw_title("noise histogram", 1);
			draw_right_histo(effect_data.ori_histo, 1);
			draw_title("Adaptive local 5.13d", 2); //5.13 d
			draw_title("noise image, 5.14a", 3); //5.14 a
			draw_title("Adaptive median, 5.14c", 4); //5.14 c
			break;
		case 4:
			draw_title("spectrum, 5.19b", 1);
			draw_title("filtered image, 5.19e", 2);
			draw_title("noise pattern, 5.19d", 3);
			break;

		case 6:
			draw_title("full filter, 5.27a", 1);
			draw_title("r = 40, 5.27b", 2);
			draw_title("r = 70, 5.27c", 3);
			draw_title("r = 85, 5.27d", 4);
			break;

		case 7:
			draw_title("inverse filter, 5.28b", 1);
			draw_title("Wiener filter, 5.28c", 2);
			break;

		case 8:
			draw_title("inverse filter, 5.29h", 1);
			draw_title("Wiener filter, 5.29i", 2);
			break;

		default:
			break;
	}
}

void interact_select(int key)
{
	if (effect_data.cmd < 10)
		return;
	if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
		//select point
		gradius = 1.0f;
		if(g_select_num < MAX_SELECT_POINTS) {
			gselect_pos[g_select_num] = GetMousePosition();
			g_select_num++;
			SetMouseCursor(MOUSE_CURSOR_POINTING_HAND);
			set_select_str_default();
		}
	} else if(key == KEY_ENTER) {
		//confirm
		Vector2 mouse = GetMousePosition();
		sprintf(g_select_str, "Select (%d, %d) OK, press 'c' to clear, 'z' to undo",
			(int)mouse.x, (int)mouse.y);
		SetMouseCursor(MOUSE_CURSOR_DEFAULT);
		int w, h;
		w = FreeImage_GetWidth(effect_data.ori);
		h = FreeImage_GetHeight(effect_data.ori);
		gradius = calc_sin_noise_r(gselect_pos, g_select_num, w, h);
	} else if(key == KEY_C) {
		//clear all datas
		gradius = 1.0f;
		g_select_num = 0;
		set_select_str_default();
	} else if(key == KEY_Z) {
		//undo
		gradius = 1.0f;
		if(g_select_num) {
			g_select_num--;
		}
	}
}

void draw_mouse_select(void)
{
	int i, w, h;
	w = FreeImage_GetWidth(effect_data.right);
	h = FreeImage_GetHeight(effect_data.right);
	//x, y of image center
	float cx = (float)w / 2;
	float cy = (float)h / 2;
	cx += effect_data.rx;
	cy += effect_data.starty;

	if (gradius > 1.0f) {
		DrawCircleLines(cx, cy, gradius, BLUE);
	}

	if(!g_select_num) {
		return;
	}

	for(i = 0; i < g_select_num; i++)
		DrawCircleV(gselect_pos[i], 5, BLUE);
}

int main(int argc, char** argv)
{
	// Initialization
	//--------------------------------------------------------------------------------------
	FreeImage_Initialise(TRUE);
	init_effect_data();
	init_fb();

	InitWindow(screenWidth, screenHeight, "ch5:图像复原与重建");
	// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
	SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
	//--------------------------------------------------------------------------------------

	int key = 0;
	int change = 0;
	Vector2 mouse = GetMousePosition();
	hint_right = "press number key";
	print_info_cn(command_str_cn, MAX_CMD_NUM);
	BYTE intensity;
	int index, max;
	max = effect_data.win_width * effect_data.win_height;

	set_select_str_default();
	// Main game loop
	while (!WindowShouldClose())    // Detect window close button or ESC key
	{
		// Update
		key = GetKeyPressed();
		if (key >= '1' && key <= '9') {
			change = 1;
			key = key - '0';
		} else if(key == KEY_DOWN || key == KEY_UP){
			change = 1;
		}
		else if(key == KEY_SPACE) {
			change = 1;
		}
		else if (key == ESC_KEY) {
			break;
		}

		interact_select(key); //mouse

		if (change) {
			change = 0;
			special_effect(key);
		}
		//----------------------------------------------------------------------------------
		//----------------------------------------------------------------------------------

		// Draw
		//----------------------------------------------------------------------------------
		BeginDrawing();
		ClearBackground(RAYWHITE);

		DrawText(hint_left, effect_data.startx, 5, 20, BLACK);
		if (hint_right) {
			DrawText(hint_right, effect_data.rx, 0, 20, BLACK);
		}
		show_info_en(command_str_en, MAX_CMD_NUM, effect_data.startx,\
			effect_data.left_max + effect_data.starty + 20);
		draw_image(effect_data.frame_buf, effect_data.win_width, effect_data.win_height);
		draw_mouse_select();
		DrawLine(effect_data.split_line, effect_data.starty,\
			effect_data.split_line, GetScreenHeight(), GRAY);
		draw_titles();

		mouse = GetMousePosition();
		index = get_window_index(mouse.y, mouse.x, effect_data.win_width);
		if(index < max) {
			intensity = effect_data.frame_buf[index].r;
			DrawText(TextFormat("(%d, %d, %d)",
				(int)mouse.x, (int)mouse.y, intensity),
				GetScreenWidth() - 160, 5, 20, BLACK);
		} else {
			DrawText(TextFormat("(%d, %d)",
				(int)mouse.x, (int)mouse.y),
				GetScreenWidth() - 160, 5, 20, BLACK);
		}

		EndDrawing();
		//----------------------------------------------------------------------------------
	}

	// De-Initialization
	destroy_effect();
	FreeImage_DeInitialise();

	//--------------------------------------------------------------------------------------
	CloseWindow();        // Close window and OpenGL context
	//--------------------------------------------------------------------------------------

	return 0;
}


